package com.ebook.server.service;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.ebook.core.domain.Book;
import com.ebook.core.util.BookUtil;
import com.ebook.jni.encryption;
import com.ebook.util.DataUtil;
import com.ebook.util.ErrorCode;
import com.ebook.util.FileUtil;
import com.ebook.util.MD5;
import com.ebook.util.Status;
import com.ebook.util.ZipUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;


@Service
@Transactional
public class BookService {

	private static final String BOOK_FILE_PATH = "/opt/ebook/data/ebooks";
	private static final String BOOK_BEFORE_UNZIP_PATH = "/opt/ebook/data/ebooks/before_unzip/";
	private static final String BOOK_AFTER_UNZIP_PATH = "/opt/ebook/data/ebooks/after_unzip/";
	private static final String BOOK_ZIP_PATH = "/opt/ebook/data/ebooks/zip/";
	
//	private static final String BOOK_FILE_PATH = "c:/opt/ebook/data/ebooks";
//	private static final String BOOK_BEFORE_UNZIP_PATH = "c:/opt/ebook/data/ebooks/before_unzip/";
//	private static final String BOOK_AFTER_UNZIP_PATH = "c:/opt/ebook/data/ebooks/after_unzip/";
//	private static final String BOOK_ZIP_PATH = "c:/opt/ebook/data/ebooks/zip/";

	
	private static Log logger = LogFactory.getLog(BookService.class); 

	@Resource
	private JdbcTemplate jdbcTemplate;
	
	@Resource
	private UserService userService;
	
	@Resource
	private DeviceBookService deviceBookService;
	
	public ModelAndView downloadEbook(int uid, int bookid,String verificationCode,
			HttpServletRequest request, HttpServletResponse response){
		ModelAndView modelView = new ModelAndView();
		Map<String, Object> modelMap = new HashMap<String, Object>();
		String status = Status.FAIL;
		
		if (!userService.isCertified(uid, verificationCode)) {
			modelMap.put("status", Status.FAIL);
			return new ModelAndView().addAllObjects(modelMap);
		}
		
	//String filePath_Name = "C:\\111.epub";
	String filePath_Name = getBookFile(uid,bookid);
		if(filePath_Name==null){
			status = Status.REJECTED + ":" + ErrorCode.BOOK_NOT_EXIST;
		}
		FileUtil.continueToDownload(filePath_Name, request, response);
		status = Status.SUCCESS;
		modelMap.put("status", status);
		modelView.addAllObjects(modelMap);
		return modelView;
	}
	public  String[] getBookidAndUserId(String ran)
	{
		  String [] temp = null ;
		  temp[0] = ran.substring(2,4) ;
		  temp[1] = ran.substring(6,10);
		  return temp ;
		    
	}
	
	
	
	
	
	
	
	/**
	 * 先把要下载的文件进行加密，然后打包
	 * @param uid
	 * @param bookid
	 * @param deviceId 设备Id
	 * @param request
	 * @param response
	 * @return status
	*/
	public ModelAndView encrypteAndCompression(int uid, int bookid,String deviceId,
			String verificationCode){
//		String fromFilePath = "/opt/ebook/data/ebooks/before_unzip/1_2\0";
//		String toFilePath = "/opt/ebook/data/ebooks/after_unzip/1\0";
		Map<String,Object> modelMap = new HashMap<String,Object>();
		if (!userService.isCertified(uid, verificationCode)) {
			modelMap.put("status", Status.FAIL);
			return new ModelAndView().addAllObjects(modelMap);
		}
		String status = Status.FAIL;
		String keyStr = getKeys(uid);
		logger.info("密钥key:"+keyStr);
		if(!deviceBookService.add(deviceId,bookid,keyStr)){
			return statusView(status);
		}
		String fileName = getBookFileToEncrypt(uid,bookid);
		StringBuilder fromFilePath = new StringBuilder(BOOK_BEFORE_UNZIP_PATH).append(fileName).append("\0");
		StringBuilder toFilePath = new StringBuilder(BOOK_AFTER_UNZIP_PATH);
		toFilePath.append(uid).append("/").append(deviceId).append("/").append(fileName).append("\0");
		int flag = encryptedEbook(keyStr, fromFilePath, toFilePath);
		if(flag == 0){
				return statusView(compressIntoEpub(uid, deviceId, fileName, toFilePath.toString()));
		}else{
			delErrorPath(toFilePath.toString());
			return statusView(status);
		}
	}
	/**
	 * 加密图书文件
	 * @param keyStr 密钥
	 * @param fromFilePath 要加密的文件路径
	 * @param toFilePath 加密后的文件路径
	 * @return 加密后的状态（0：成功；其他：失败）
	*/
	private int encryptedEbook(String keyStr, StringBuilder fromFilePath,
			StringBuilder toFilePath) {
		logger.info("fromFilePath : "+fromFilePath);
		logger.info("toFilePath : "+toFilePath);
		File f=new File(toFilePath.substring(0, toFilePath.lastIndexOf("/")));
		 if(!f.exists()){
		   f.mkdirs();
		  }
		byte[] src_path;
		byte[] des_path;
		byte[] key;
		int flag = 111111;
		src_path = fromFilePath.toString().getBytes();
		logger.info("fromFilePath:byte数组的长度为： " + src_path.length);
		logger.info(src_path[src_path.length-1]);
		des_path = toFilePath.toString().getBytes();
		logger.info("toFilePath:byte数组的长度为： " + des_path.length);
		logger.info(des_path[des_path.length-1]);
		key = (keyStr+"\0").getBytes();
		logger.info("key:byte数组的长度为： " + key.length);
		logger.info(key[key.length-1]);
		byte[] prikey = new byte[200];
		int type = 128;
		int encrypt_type = 0;
		byte[] version = new byte[1024];
		flag = encryption.book_encrypt(src_path, des_path, key, type, prikey,encrypt_type, version);
		logger.info("jni_flag: " + flag);
		return flag;
	}
	
	/**
	 * 压缩成.epub格式的文件，并返回status
	 * @param uid 
	 * @param deviceId 设备id
	 * @param fileName 文件名
	 * @param toFilePath 要压缩的文件路径
	 * @return Success:成功；Fail:失败
	*/
	private String compressIntoEpub(int uid, String deviceId,
			String fileName, String toFilePath) {
		StringBuilder destPath = new StringBuilder(BOOK_ZIP_PATH);
		destPath.append(uid).append("/").append(deviceId).append("/").append(fileName).append(".epub");
		try {
			File ff =new File(destPath.substring(0, destPath.lastIndexOf("/")));
			 if(!ff.exists()){
			   ff.mkdirs();
			  }
			long start = System.currentTimeMillis();
			ZipUtils.compress(toFilePath.substring(0, toFilePath.length()-1), destPath.toString());
			long end = System.currentTimeMillis();
			logger.info("压缩文件用时："+(end-start)+" ms");
			return Status.SUCCESS;
		} catch (Exception e){
			logger.error("压缩文件操作错误！"+e);
			delErrorPath(toFilePath.toString(),destPath.toString());
			throw new RuntimeException(e);
		}	
	}
	
	/**
	 * 删除错误的加密文件路径
	 * @param toFilePath 加密后的文件路径
	*/
	private void delErrorPath(String toFilePath){
		try {
			logger.info("删除toFilePath："+toFilePath);
			FileUtils.deleteDirectory(new File(toFilePath));	
		} catch (IOException e) {
			logger.error("删除文件路径错误！"+e);
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 删除加密后文件路径和压缩后的错误文件
	 * @param toFilePath 加密后的文件路径
	 * @param zipPath 压缩后文件路径
	*/
	private void delErrorPath(String toFilePath,String zipPath){
		delErrorPath(toFilePath);
		logger.info("删除zipPath:"+zipPath);
		new File(zipPath).delete();
	}
	/**
	 * 返回视图并返回status值
	 * @param status Success：成功；其他：失败
	 * @return 状态值
	*/
	private ModelAndView statusView(String status){
		Map<String,Object> modelMap = new HashMap<String, Object>();
		modelMap.put("status", status);
		return new ModelAndView().addAllObjects(modelMap);
	}
	
	/**
	 * 断点续传下载
	 * @param uid
	 * @param bookid
	 * @param deviceId
	 * @param request
	 * @param response
	 * @return 
	*/
	public ModelAndView continueToDownload(int uid, int bookid,
			String deviceId, String verificationCode,HttpServletRequest request,
			HttpServletResponse response) {
		if (!userService.isCertified(uid, verificationCode)) {
			Map<String,Object> modelMap = new HashMap<String, Object>();
			modelMap.put("status", Status.FAIL);
			return new ModelAndView().addAllObjects(modelMap);
		}
		String fileName = getBookFileToEncrypt(uid,bookid);
		StringBuilder destPath = new StringBuilder(BOOK_ZIP_PATH);
		destPath.append(uid).append("/").append(deviceId).append("/").append(fileName).append(".epub");
		FileUtil.continueToDownload(destPath.toString(), request, response);
		return new ModelAndView();	
	}
	
	/**
	 * 将图书封面图片存到数据库中
	 * @param picFile 图片文件
	 * @param bookId  图书id
	 * @return 成功失败信息
	*/
	public ModelAndView addCoverPic(MultipartFile picFile, int bookId) {
		ModelAndView modelView = new ModelAndView();
		Map<String, Object> modelMap = new HashMap<String, Object>();
		String status = Status.SUCCESS;
		if (addCoverPic(bookId, picFile) == false) {
			status = Status.REJECTED + ":" + ErrorCode.FAIL;
		}
		modelMap.put("status", status);
		modelView.addAllObjects(modelMap);
		return modelView;
	}
	
	/**
	 * 通过图书id获取图书对象
	 * @param id 图书id
	 * @return   图书信息对象
	 */
	public Book getBookInfo(int id) {
		String sql = "select * from book where id = ?";
		logger.info(sql);
		Book book = null;
		try {
				Map<String, Object> map = jdbcTemplate.queryForMap(sql, id);
				book = BookUtil.parseBook(map);
				return book;
		} catch (DataAccessException e) {
			return null;
		}		
	}

	/**
	 * 通过uid 和 bookid 获取文件路径名
	 * @param uid
	 * @param bookid
	 * @return 文件路径名 或 null
	*/
	public String getBookFile(int uid,int bookid) {
		if (bookid < 0) {
			return null;
		}
		String sql2 = "SELECT b.book_path from book as b , user_book as ub where ub.bookid=b.id and ub.userid=? and b.id=?";
		logger.info(sql2);
		try {  
			//Object[] params = new Object[] { sql2, uid, bookid }; 
				Map<String, Object> map = jdbcTemplate.queryForMap(sql2, new Object[] { uid, bookid });

			    if (!map.isEmpty()) {
				String fileName = (String)map.get("book_path");
				if (fileName != null) {
					String filePath_Name = BOOK_FILE_PATH + "/" + fileName;
					File f=new File(BOOK_FILE_PATH);
					 if(!f.exists()){
					   f.mkdirs();
					  }
					return filePath_Name;	
				}
			}
		} catch (DataAccessException e) {
			return null;
		}
		return null;	
	}
	
	/**
	 * 通过uid 和 bookid 获取文件路径名
	 * @param uid
	 * @param bookid
	 * @return 文件路径名 或 null
	*/
	public String getBookFileToEncrypt(int uid,int bookid) {
		if (bookid < 0) {
			return null;
		}
		String sql = "SELECT b.book_path from book as b , user_book as ub where ub.book_id=b.id and ub.user_id=? and b.id=?";
		logger.info(sql);
		try {
				Map<String, Object> map = jdbcTemplate.queryForMap(sql,uid,bookid);
			if (map != null) {
				String fileName = (String)map.get("book_path");
				if (fileName != null) {
//					String filePath_Name = BOOK_FILE_ENCRYPTE_PATH + "//" + fileName;
//					File f=new File(BOOK_FILE_ENCRYPTE_PATH);
//					 if(!f.exists()){
//					   f.mkdirs();
//					  }
					return fileName.substring(0, fileName.lastIndexOf("."));	
				}
			}
		} catch (DataAccessException e) {
			return null;
		}
		return null;	
	}
	


	
	/**
	 * 添加图书封面图片
	 * @param bookId 图书id
	 * @param file 笔记对应的数据文件,将存放在数据库中
	 * @return true。失败返回false
	 */
	public boolean addCoverPic(int bookId, MultipartFile file) {
		String sql = "update book set pic = ? where id = ?";
		try {
			byte[] data = file.getBytes();
			jdbcTemplate.update(sql, data, bookId);
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	 * 获取本地不存在的图书
	 * @param uid
	 * @param bookidsJson
	 * @param request
	 * @return 图书列表
	*/
	public ModelAndView getNewBooks(int uid, String bookidsJson,String verificationCode) {
		Map<String, Object> modelMap = new HashMap<String, Object>();
		List<Book> bookList = null;
		if(!userService.isCertified(uid, verificationCode)){
			modelMap.put("status", Status.FAIL);
			return new ModelAndView().addAllObjects(modelMap);
		}
		Gson gson = new Gson();
		List<Book> list = gson.fromJson(bookidsJson, new TypeToken<List<Book>>() {
		}.getType());
		bookList = getBookByNoBookids(uid, list);
		modelMap.put("bookList", bookList);
		modelMap.put("status", Status.SUCCESS);
		return new ModelAndView().addAllObjects(modelMap);
		
	}
	/**
	 * 获取bookids 不存在的图书信息
	 * @param uid
	 * @param list
	 * @return 图书链表
	 * 
	 * 获取 最新图书列表 
	 * 修改为 对用户id 不做校验 ,只查询用户没有的book id
	*/
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	private List<Book> getBookByNoBookids(int uid, List<Book> list) {
		List<Book> bookList = new ArrayList<Book>();
		StringBuilder selectNoBookidSql = new StringBuilder("" +"select  b.* from user_book as ub,book b  ");
		 int length = list.size();
		if(length>0)
		{
			selectNoBookidSql.append("where ");
	   if( length==1)
				selectNoBookidSql.append("  b.id!='").append(list.get(0).getId()).append("'");
			else{
				selectNoBookidSql.append("  b.id!='").append(list.get(0).getId()).append("'");
		     for (int i = 1; i < list.size(); i++) {
			selectNoBookidSql.append(" and b.id!='").append(list.get(i).getId()).append("'");	
		}
			}
	   
		}
		logger.info(selectNoBookidSql);	
		List<Map<String, Object>> maps1 = jdbcTemplate.queryForList(selectNoBookidSql.toString());  
		if(maps1.size() <= 0){
			return bookList;
		}
		for (Map<String, Object> map : maps1) {
			Book book = BookUtil.parseBook(map);
			if (book != null) {
				bookList.add(book);
			}
		}
		return bookList;	
	}
	
	/**
	 * 下载成功后删除临时生成的文件及路径，并发放密钥
	 * @param uid
	 * @param bookid
	 * @param deviceId
	 * @return 密钥信息
	*/
	public ModelAndView downSuccessfulOperation(int uid,int bookid,String deviceId,String verificationCode) {
		ModelAndView modelView = new ModelAndView();
		Map<String, Object> modelMap = new HashMap<String, Object>();
		if (!userService.isCertified(uid, verificationCode)) {
			modelMap.put("status", Status.FAIL);
			return new ModelAndView().addAllObjects(modelMap);
		}
		delFilePath(uid,bookid,deviceId);
		modelMap.put("keys", deviceBookService.findKeys(deviceId, bookid));
		modelView.addAllObjects(modelMap);
		return modelView;		
	}
	

	/**
	 * 删除加密后的临时文件
	 * @param uid
	 * @param bookid
	 * @param deviceId 
	*/
	private void delFilePath(int uid, int bookid, String deviceId) {
		String fileName = getBookFileToEncrypt(uid,bookid);
		StringBuilder unZipPath = new StringBuilder(BOOK_AFTER_UNZIP_PATH);
		unZipPath.append(uid).append("/").append(deviceId).append("/").append(fileName);
		StringBuilder zipPath = new StringBuilder(BOOK_ZIP_PATH);
		zipPath.append(uid).append("/").append(deviceId).append("/").append(fileName).append(".epub");
		delErrorPath(unZipPath.toString(), zipPath.toString());
	}
	/**
	 * 创建24位随机码（16位userId+8位随机码）
	 * @param uid
	 * @return 字符串
	*/
	private String getKeys(int uid) {
		int len = String.valueOf(uid).length();
		StringBuilder sb = new StringBuilder();
		for(int i=0;i<16-len;i++){
			sb.append("0");
		}
		sb.append(uid);
		sb.append(DataUtil.generateRandomString(8));
		return sb.toString();
		
	}
	
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public Map<String, Object> addTest() {
		Map<String, Object> modelMap = new HashMap<String, Object>();
		String sql = "insert into test1 (age) values (?)";
		for(int i=1;i<=2;i++){
			{
				jdbcTemplate.update(sql, i);
			}
		}
		String sql1 = "delete from test1 where age=?";
		modelMap.put("value", jdbcTemplate.update(sql1,1));
		modelMap.put("value1", jdbcTemplate.update(sql1, "name",1));
		return modelMap;
		
	}


	public void setBookPath() {
		String sql = "select * from book ";
		String sql2 = "update book set book_path=? where id=?";
		List<Map<String,Object>> list = jdbcTemplate.queryForList(sql);
		for(Map<String,Object> m : list){
			String str = m.get("id").toString()+"_"+m.get("name").toString()+".epub";
			System.out.println(str);
			jdbcTemplate.update(sql2, str,(Integer)(m.get("id")));
		}
		
	}
	/**
	 * 超级码验证
	 * @param uid
	 * @param bookid
	 * @param deviceId 
	*/
	

	public ModelAndView validate(int uid, String verificationCode,
			HttpServletRequest request, HttpServletResponse response){
		ModelAndView modelView = new ModelAndView();
		Map<String, Object> modelMap = new HashMap<String, Object>();
		String status = Status.FAIL;
		Map<String, Object> code =  new HashMap<String, Object>();
	//	 verificationCode = "0OD1FPTWE2fy" ;
		  String crypt = MD5.getEncryptedPwd(verificationCode);
		  
		  if(verificationCode !=null)
		  {
			  String partnerid = verificationCode.substring(2,4);
			     partnerid = Pattern(partnerid);
			  String bookid   = verificationCode.substring(6,10);
			            bookid  = Pattern(bookid);				            
               //查找密钥 
		     code =getCode(Integer.parseInt(partnerid),crypt);
		  
		       if( code.size()!=0)   
		       {  
		            status = Status.SUCCESS;
				modelMap.put("status", status);
				modelView.addAllObjects(modelMap);
				return modelView;
			  
		       }
		       else		  
				  { modelMap.put("status", Status.FAIL);
						return new ModelAndView().addAllObjects(modelMap);
				  
				  } 
		  }	
		  modelMap.put("status", Status.FAIL);
			return new ModelAndView().addAllObjects(modelMap);
	
	}
	/**
	 * 超级码删除
	 * @param uid
	 * @param bookid
	 * @param deviceId 
	*/

	public ModelAndView  deleteCode(int uid, String verificationCode,
			HttpServletRequest request, HttpServletResponse response){
		ModelAndView modelView = new ModelAndView();
		Map<String, Object> modelMap = new HashMap<String, Object>();
		String deletesql = " delete  from partenInfo where partnerid=? and code= ?" ;
		String insertsql = "insert into seller ( partnerid, bookid,userid,useremail,date) values (?, ?, ?, ?, ?)";
		String  selectsql = "select email  from user where id=?";
		String status = Status.FAIL;
	//	Date date = new Date(); 
	    Date dt = new Date();  
	    //最后的aa表示“上午”或“下午”    HH表示24小时制    如果换成hh表示12小时制  
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm  aa");  
	    String temp_date =sdf.format(dt);  
	    
		Map<String, Object> code =  new HashMap<String, Object>();
		  String crypt = MD5.getEncryptedPwd(verificationCode);		  
		  if(verificationCode !=null)
		  {
			  String partnerid = verificationCode.substring(2,4);
			     partnerid = Pattern(partnerid);
			  String bookid   = verificationCode.substring(6,10);
			            bookid  = Pattern(bookid);				            
               //查找密钥 
		     code =getCode(Integer.parseInt(partnerid),crypt); 
		       if( code.size()!=0)   
		       {  
		          
		         if(jdbcTemplate.update(deletesql,Integer.parseInt(partnerid),crypt)!=0)
		          { logger.debug("删除 验证码ok:"+verificationCode);
		          Map<String, Object> emil =   jdbcTemplate.queryForMap(selectsql, uid);
		           String email = (String) emil.get("email");
		           if(   jdbcTemplate.update(insertsql,Integer.parseInt(bookid), uid,Integer.parseInt(partnerid),email,temp_date)==1) 
		        	   logger.debug("增加seller id");
		           
		           status = Status.SUCCESS;
					modelMap.put("status", status);
					modelView.addAllObjects(modelMap);
				     return modelView;
		          }
				    else
				   {
				    	logger.debug("删除 验证码错误："+verificationCode);
				    	 modelMap.put("status", Status.FAIL);
							return new ModelAndView().addAllObjects(modelMap);
				    //	return "error";
				   }
		        	 
		       }
		       
		      
		  }	
		    
		  modelMap.put("status", Status.FAIL);
			return new ModelAndView().addAllObjects(modelMap);
	
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	public  String  Pattern(String ran)
	{   
		         if (ran!=null) {
		             Pattern p = Pattern.compile("[a-zA-Z]");;
		          ran = ran.replaceAll("[a-zA-Z]", "");
		        }
	
		  return ran ;
		    
	}
	public   Map<String, Object> getCode(int partnid ,String code )
	{        Map<String, Object> map ;
	 String sqlCode = "select code from partenInfo where partnerid=? and code = ?" ;
		        if(  partnid >0)
		        {
		        map =	 jdbcTemplate.queryForMap(sqlCode, partnid,code);	
		        	
		        }
		        else 
		              return  null; 
		  return map ;
		    
	}
	
	

	
}
